什么是Vue
Vue是构建用户界面的 JavasScript
的 MVVM
框架。
那么到底什么是 MVVM
- M(Model):数据层;例如 Vue2 实例中的 data
- V(View):视图(DOM)
- VM(ViewModel):Vue胶水层代码;它负责 监听数据的变化 和 视图的更新,同时也是
Model
数据 和View
视图通信的一个桥梁
MVVM
又叫数据驱动视图,所以视图的改变源于数据的更新。
Vue
在实例化的过程中会对遍历传给 实例化对象选项中的 data
选项 遍历其所有属性 并使用 Object.defineProperty
把这些属性全部转为 getter
/setter
。
Vue
最重要的两个 function
监听 Observer
和 编译 Compile
Observer
- Observer 基本干了什么事情
- 劫持并监听所有属性
- 在 Observer 函数中
- 采用的方式
- Vue2 Object.defineProperty
- Vue3 new Proxy
- 劫持并监听所有属性
export class Observer {
value: any;
dep: Dep;
vmCount: number;
constructor (value: any) {
this.value = value
// 一个 Dep 对象的实例,Watcher 和 Observer 之间的桥梁
this.dep = new Dep()
this.vmCount = 0
// 把自身 this 添加到 value 的 __ob__ 属性上
def(value, '__ob__', this)
// 对 value 的类型进行判断
if (Array.isArray(value)) {
if (hasProto) {
protoAugment(value, arrayMethods)
} else {
copyAugment(value, arrayMethods, arrayKeys)
}
this.observeArray(value)
} else {
this.walk(value)
}
}
}
常见问题
data
为什么需要是个函数- 因为
js
的对象是按引用传递的,如果使用对象的话,会导致组件内数据无法保持唯一,可能会被其他组件数据修改,所以需要使用函数,每次都重新创建一个新的对象实现。
- 因为
响应式原理
通过
definePropery
对data
内的属性遍历添加getter
、setter
属性,通过watcher
对Dep
进行依赖收集管理,内部会通过Dep.target
去维护一个当前的watcher
,当数据更新的时候会去执行dep.notify
方法,依次遍历当前dep
内的watcher
进行数据更新。Observer
用于添加getter
和setter
。Dep
进行依赖收集 (收集的依赖就是watcher
)。Watcher
主要负责保存依赖,从而在数据更新的时候,触发渲染。
- data watcher
- watch watcher
- computed watcher
- 在实例上保存了个
lazy
和dirty
属性。 - 如果当前的
dirty
为true
,说明就需要重新计算,则调用watcher.evaluate
方法进行计算。 watcher
创建的时候,默认是不会调用get
方法进行依赖收集。- 只有在数据发生变化的时候,会去调用
watcher.update
, 然后再这里面调用watcher.run
,进而去调用get
方法收集依赖,或者数据发生变化的时候,也会重新收集依赖。
- 在实例上保存了个
computed
- 调用
initComputed
进行初始化,对computed
内的每个对象创建一个watcher
。 - 如果
computed
是个函数,就调用createComputedGetter
否则调用createGetterInvoker
,并通过defineProperty
挂载到实例上,重写get
方法。
watch
- 调用
initWatch
进行初始化,并对watch
内的每个属性,创建一个watcher
。 - 如果
val
是对象,贼调用val.handler
,是string
,则从this
中获取,否则val
就是个函数 - 对
watch
的每个属性调用vm.$watch
进行处理 - 依然创建一个watcher,如果当前 watch 有 immediate 属性,则立刻执行
性能指标
FP(First Paint)首次绘制 FCP (First Contentful Paint) 首次内容绘制 LCP(Largest Contentful Paint)最大内容绘制 DCL (DocumentContentLoaded) dom加载完成 L (Onload)页面加载完成 TTI(Time To Interactive)可交互 TBT (Total Blocking Time)页面阻塞总时长 FID (First Input Delay)首次输入延迟 CLS (Cumlative Layout Shift)累计布局偏移 SI (Speed Index) 首次显示页面可见部分的平均时间
雅虎35条军规前端性能优化之雅虎35条军规
服务器
- 使用cdn
- 使用浏览器缓存
- 启用gzip
- 配置etag
- ajax使用get请求(get可以被缓存,post不会)
- 避免图片src为空
- 尽早输出内容(服务端渲染)
页面内容
- 减少http请求
- 减少dns查询
- 避免重定向
- 缓存ajax请求
- 延迟加载
- 预加载
- 减少dom元素数量
- 划分内容到不同域名
- 减少iframe使用
- 减少404
- 保持单个文件小于25kb
- 打包内容为分段multipart文档
Cookie
- 减少cookie大小
- 静态资源使用无cookie的域名
图片
- 尽可能使用webp
- css sprite(雪碧图)
- 使用体积小,可缓存的favicon.ico
js
- script放页面底部
- 使用外部 js 和 css
- 压缩 css js
- 删除重复脚本
- 减少dom操作
- 使用高效的事件处理
css
- 把样式表放在head内
- 不用使用css表达式
- 使用link代替@import
- 不要使用filter(不是css3的filter,ie的东西)
重排重绘的操作读写分离 getComputedStyle currentStyle
重排: 页面初始渲染,这是开销最大的一次重排 添加/删除可见的DOM元素 改变元素位置 改变元素尺寸,比如边距、填充、边框、宽度和高度等 改变元素内容,比如文字数量,图片大小等 改变元素字体大小 改变浏览器窗口尺寸,比如resize事件发生时
重绘: 当一个元素的外观发生改变,但没有改变布局,重新把元素外观绘制出来的过程,叫做重绘
1.HTML 被 HTML 解析器解析成 DOM 树; 2.CSS 被 CSS 解析器解析成 CSSOM 树; 3.结合 DOM 树和 CSSOM 树,生成一棵渲染树(Render Tree),这一过程称为 Attachment; 4.生成布局(flow),浏览器在屏幕上“画”出渲染树中的所有节点; 5.将布局绘制(paint)在屏幕上,显示出整个页面。 第四步和第五步是最耗时的部分,这两步合起来,就是我们通常所说的渲染。